//////////////////////////////////////////////////////////////////////////

#ifndef _BOOSTCONNECTIONIMPL_H_
#define _BOOSTCONNECTIONIMPL_H_

//////////////////////////////////////////////////////////////////////////

#ifndef _CONNECTIONIMPL_H_
#include "connectionimpl.h"
#endif

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <vector>
#include <map>

//////////////////////////////////////////////////////////////////////////

using boost::asio::io_service;
using boost::system::error_code;
using boost::asio::ip::tcp;
using boost::asio::ip::udp;

//////////////////////////////////////////////////////////////////////////


/** Connection between client and server
*
*  @author   Pasechnik Roman
*  @since    Jun 30th, 2009
*  @updated  Sep 08th, 2009
*/
class BoostConnectionImpl : public ConnectionImpl
{
//////////////////////////////////////////////////////////////////////////

public:

//////////////////////////////////////////////////////////////////////////


    /** Constructor */
    BoostConnectionImpl();


    /** Destructor */
    virtual ~BoostConnectionImpl();


//////////////////////////////////////////////////////////////////////////


    /** Send TCP */
    virtual void SendTCP( const Packet& _packet );


    /** Send UDP */
    virtual void SendUDP( const Packet& _packet );


//////////////////////////////////////////////////////////////////////////


    /** Connect to server (client only) */
    virtual void Connect( const char* _address );


    /** Accept new connection (server only) */
    virtual void Accept();


    /** Close connection */
    virtual void Close();


//////////////////////////////////////////////////////////////////////////

private:

//////////////////////////////////////////////////////////////////////////

    enum { MAX_BUFFER_SIZE = 1024 };
    char m_RecvBufferTCP[MAX_BUFFER_SIZE];
    static char m_RecvBufferUDP[MAX_BUFFER_SIZE];

//////////////////////////////////////////////////////////////////////////


    /** Working mode */
    enum Mode
    {
        INVALID,
        CLIENT,
        SERVER
    };
    static Mode m_Mode;


//////////////////////////////////////////////////////////////////////////


    /** Start receive UDP packets */
    void StartReceiveTCP();


    /** Start receive TCP packets */
    static void StartReceiveUDP();


//////////////////////////////////////////////////////////////////////////


    /** Handle accept */
    void HandleAccept( const error_code& _error );


//////////////////////////////////////////////////////////////////////////


    /** Handle sent TCP packet */
    void HandleSendTCP( const error_code& _error,
                        size_t _bytesTransferred );


    /** Handle sent UDP packet */
    void HandleSendUDP( const error_code& _error,
                        size_t _bytesTransferred );


//////////////////////////////////////////////////////////////////////////


    /** Handle received TCP packet */
    void HandleRecvTCP( const error_code& _error,
                        size_t _bytesTransferred );


    /** Handle received UDP packet */
    static void HandleRecvUDP( const error_code& _error,
                               size_t _bytesTransferred );


//////////////////////////////////////////////////////////////////////////

private:

//////////////////////////////////////////////////////////////////////////


    /** TCP socket */
    tcp::socket m_TCPSocket;
    

    /** TCP endpoint */
    tcp::endpoint m_TCPEndpoint;
    

//////////////////////////////////////////////////////////////////////////


    /** IO_SERVICE object [Singleton] */
    static io_service* m_IOService;


    /** IO_SERVICE accessor */
    static io_service* GetIOService();


//////////////////////////////////////////////////////////////////////////


    /** TCP acceptor [Singleton] */
    static tcp::acceptor* m_Acceptor;


    /** TCP acceptor accessor */
    static tcp::acceptor* GetTCPAcceptor();


//////////////////////////////////////////////////////////////////////////

    /** UDP socket [Singleton] */
    static udp::socket* m_UDPSocket;


    /** UDP socket accessor */
    static udp::socket* GetUDPSocket();


//////////////////////////////////////////////////////////////////////////


    /** UDP endpoint for sending packets */
    static udp::endpoint m_UDPSendEndpoint;


    /** UDP endpoint for receiving packets */
    static udp::endpoint m_UDPRecvEndpoint;


////////////////////////////////////////////////////////////////////////////////


    /** Get UDP endpoint by connection */
    static udp::endpoint GetUDPEndpoint( BoostConnectionImpl* _this );


////////////////////////////////////////////////////////////////////////////////

private:

////////////////////////////////////////////////////////////////////////////////


    /** Thread in which boost connection works */
    static boost::thread m_Thread;


    /** Tells if thread is started or stopped */
    static bool m_Started;


    /** Tells if UDP accept started or stopped */
    static bool m_UDPAcceptStarted;


    /** Run async operations (send, recv) */
    static void Run();


    /** Thread procedure, where async operations are running */
    static void ThreadProc();


////////////////////////////////////////////////////////////////////////////////

private:

////////////////////////////////////////////////////////////////////////////////


    typedef std::map<udp::endpoint, BoostConnectionImpl*> ConnectionsByEndpoints;
    static ConnectionsByEndpoints m_ConnectionsByEndpoints;


    typedef std::map<BoostConnectionImpl*, udp::endpoint> EndpointsByConnections;
    static EndpointsByConnections m_EndpointsByConnections;


//////////////////////////////////////////////////////////////////////////
};

//////////////////////////////////////////////////////////////////////////

#endif

//////////////////////////////////////////////////////////////////////////
